/*
 * Daniel R Padilla
 *
 * Copyright (c) 2007, Daniel R Padilla
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.databasefacade;


import java.io.File;
import java.sql.Connection;
import java.util.Iterator;

import org.databasefacade.create.TableRegistrySynchronizer;
import org.databasefacade.data.ColumnDataValue;
import org.databasefacade.exception.DatabaseFacadeException;
import org.databasefacade.query.QueryResultsList;
import org.databasefacade.registry.TableRegistry;
import org.databasefacade.registry.TableRegistryLoader;
import org.databasefacade.statements.DatabaseStatement;
import org.databasefacade.statements.DeleteStatement;
import org.databasefacade.statements.InsertStatement;
import org.databasefacade.statements.SelectStatement;
import org.databasefacade.statements.UpdateStatement;
import org.databasefacade.table.Table;
import org.databasefacade.table.row.Row;
import org.databasefacade.translator.Translator;
import org.databasefacade.translator.TranslatorFactory;
import org.databasefacade.xml.XMLConnectionPropertiesLoader;


/**
 * The public interface for accessing the database. We
 * want a central point so that it is easier to support
 * multiple databases types and multiple database 
 * connections.
 * 
 * The ansiSQL-92 type implements all functions using
 * ansiSQL-92 standards. The core code should not use any
 * database queries that cannot be supported by ansiSQL-92
 */
public class DatabaseFacade implements DatabaseFacadeConst
{
	private DatabaseHelper dbHelper = new DatabaseHelper();
	private TableRegistry tableRegistry = new TableRegistry();
	private boolean isInitialized = false;

	public DatabaseFacade(File connFile, short initType) 
	{
		try {
			if ( initType == FULL_INITIALIZATION ) {
				fullInitialization(connFile);
			} else if ( initType == LITE_INITIALIZATION ) {
				liteInitialization(connFile);
			} else {
				throw new Exception("Invalid initialization type was passed");
			}
		} catch ( Exception e ) {
			e.printStackTrace();
			throw new RuntimeException("Could not initialize the DatabaseFacade");
		}
		isInitialized = true;
	}
	
	public DatabaseFacade(File connFile)
	{
		try {
			fullInitialization(connFile);
		} catch ( Exception e ) {
			e.printStackTrace();
			throw new RuntimeException("Could not initialize the DatabaseFacade");
		}
		isInitialized = true;
	}
	
	/**
	 * Initializes enough to test query output
	 * 
	 * @param dbType
	 */
	public DatabaseFacade(int dbType)
	{
		dbHelper.setTranslator(TranslatorFactory.getDatabaseTranslator(dbType));
		isInitialized = true;
	}
	
	public TableRegistry getTableRegistry() 
	{
		return tableRegistry;
	}
    
	public DatabaseHelper getDatabaseHelper() 
	{
		return dbHelper;
	}
    
	public void registryTableSynchronize()
		throws DatabaseFacadeException
	{
		TableRegistrySynchronizer synchronizer = new TableRegistrySynchronizer();
		synchronizer.synchRegistryTables(tableRegistry, dbHelper);
	}
    
	/*
	 * Database access methods
	 */
	public Connection getConnection()
		throws DatabaseFacadeException
	{
		return dbHelper.getConnection();
	}
    
	/*
	 * Transaction option methods. Built to encourage short transactions
	 * with no java processing between statements.
	 */
	public void transaction(DatabaseStatement[] statements, Connection conn) 
		throws DatabaseFacadeException
	{
		checkInitialization();
    	
	}
    
	/*
	 * Update option methods
	 */
	public void update(Row row, Connection conn, SessionTracker session) 
		throws DatabaseFacadeException
	{
		checkInitialization();
	}
    
	public void update(UpdateStatement stmt, Connection conn) 
		throws DatabaseFacadeException
	{
		checkInitialization();
	}
    
	/*
	 * Insert option methods
	 */
	public void insert(Row row, Connection conn, SessionTracker session) 
		throws DatabaseFacadeException
	{
		checkInitialization();
	}
    
	public void insert(InsertStatement stmt, Connection conn) 
		throws DatabaseFacadeException
	{
		checkInitialization();
	}
	
	/*
	 * Delete option methods
	 */
	public void delete(Row row, Connection conn, SessionTracker session) 
		throws DatabaseFacadeException
	{
		checkInitialization();
	}
	
	public void delete(DeleteStatement stmt, Connection conn) 
		throws DatabaseFacadeException
	{
		checkInitialization();
	}
    
	/*
	 * Select Option Methods
	 */
	public QueryResultsList select(SelectStatement select, Connection conn)
	{
		return null;
	}
    
	public QueryResultsList select(SelectStatement select, Object[] params, Connection conn)
	{
		return null;
	}
    
	public QueryResultsList select(SelectStatement select, Iterator params, Connection conn)
	{
		return null;
	}
    
	public QueryResultsList select(Table table, Connection conn)
	{
		return null;
	}
    
	public QueryResultsList select(Table table, ColumnDataValue primaryKey, Connection conn)
	{
		return null;
	}
    
	/*
	 *  Support Methods
	 */
	public void setStringDelimiter(String del)
		throws DatabaseFacadeException
	{
		checkInitialization();
		dbHelper.getTranslator().setStringDelimiter(del);
	}
	
	public String getStringDelimiter()
	{
		return dbHelper.getTranslator().getStringDelimiter();
	}
	
	public int getDatbaseType()
		throws DatabaseFacadeException
	{
		checkInitialization();
		return dbHelper.getDatabaseType();
	}
	
	public Translator getDatabaseTranslator()
	{
		return dbHelper.getTranslator();
	}
	
	/*
	 * Initialization methods
	 */
	private void fullInitialization(File connFile) 
		throws DatabaseFacadeException
	{
		initConnectionProperties(connFile);
		initConnection(connFile);
		initRegistry(connFile);
	}
	
	private void liteInitialization(File connFile) 
		throws DatabaseFacadeException
	{
		initConnectionProperties(connFile);
		initConnection(connFile);
	}
    
	private void initConnectionProperties(File connFile)
		throws DatabaseFacadeException
	{
		XMLConnectionPropertiesLoader loader = new XMLConnectionPropertiesLoader();
		dbHelper.setConnectionProps(loader.load(connFile));
	}
    
	private void initConnection(File connFile) 
		throws DatabaseFacadeException
	{
		if ( dbHelper.getConnectionProps() == null ) {
			initConnectionProperties(connFile);
		}
		dbHelper.getConnectionManager().init(dbHelper.getConnectionProps());
		dbHelper.setTranslator(
			TranslatorFactory.getDatabaseTranslator(
				dbHelper.getConnectionProps().getDatabaseType()));
		isInitialized = true;
	}
    
	private void initRegistry(File connFile)
		throws DatabaseFacadeException
	{
		try {
			if ( dbHelper.getConnectionProps() == null ) {
				initConnectionProperties(connFile);
			}
		
			if ( dbHelper.getConnectionProps().getMetaDataDir() == null ) {
				dbHelper.getConnectionProps().setMetaDataDir(
					connFile.getAbsolutePath() + "\\" + "dbfacadeDatabaseSchema.xml");
			}
		
			if ( dbHelper.getConnectionProps().getMetaDataDir() != null ) {
				File metaFile = new File(dbHelper.getConnectionProps().getMetaDataDir());
				TableRegistryLoader loader = new TableRegistryLoader();
				loader.addXmlDefinitions(tableRegistry, dbHelper.getTranslator(), metaFile);
			}
		} catch ( Exception e ) {
			throw new DatabaseFacadeException(e);
		}
	}
    
	/*
	 *  Private methods 
	 */
	private void checkInitialization()
		throws DatabaseFacadeException
	{
		if ( !isInitialized ) {
			throw new DatabaseFacadeException(
				"The Daniel R Padilla has not been initialized and cannot be used.");
		}
	}
    
	/*
	 * Test Main
	 */
	public void main(String args[])
		throws Exception
	{
		String filePath = args[0];
		File file = new File(filePath);
		
		DatabaseFacade facade = new DatabaseFacade(file);
		
		Connection conn = facade.getConnection();

		conn.close();
	}
}
